/**************************************************************************
 *
 * Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
 *
 * SPDX-License-Identifier: MIT
 *
 *********************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include "hardware.h"
/* me */
#include "adc.h"

/* prescale select bits */
#if (F_CPU >> 1) < 1000000
#define ADPS_8BIT (1)
#define ADPS_10BIT (3)
#elif (F_CPU >> 2) < 1000000
#define ADPS_8BIT (2)
#define ADPS_10BIT (4)
#elif (F_CPU >> 3) < 1000000
#define ADPS_8BIT (3)
#define ADPS_10BIT (5)
#elif (F_CPU >> 4) < 1000000
#define ADPS_8BIT (4)
#define ADPS_10BIT (6)
#elif (F_CPU >> 5) < 1000000
#define ADPS_8BIT (5)
#define ADPS_10BIT (7)
#else
#error "ADC: F_CPU too large for accuracy."
#endif

/* ADMUX: channel bits 0..4
      ADLAR = Left Adjust Result
      REFSx = hardware setup: cap on AREF
*/
/* ADCSRA:
      ADEN = Enable
      ADSC = Start conversion
      ADIF = Interrupt Flag
      ADIE = Interrupt Enable
      ADATE = Auto Trigger Enable
*/

void adc_enable(uint8_t index)
{
    index = index;
    /* do nothing */
}

/**************************************************
 * Description: Run a Analog to Digital conversion
 * Returns: none
 * Notes: none
 **************************************************/
uint8_t adc_result_8bit(uint8_t channel)
{ /* 0..7 = ADC0..ADC7, respectively */
    uint8_t value = 0; /* return value */

    while (ADCSRA & (1 << ADSC))
        ;
    ADMUX = channel | (1 << ADLAR) | (0 << REFS1) | (1 << REFS0);
    /* Delay needed for the stabilization of the ADC input voltage */
    _delay_us(10);
    /* Start the analog to digital conversion */
    ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIF) | ADPS_8BIT;
    /* Wait for the analog to digital conversion to complete */
    while ((ADCSRA & (1 << ADIF)) == 0)
        ;
    value = ADCH;

    return value;
}

/**************************************************
 * Description: Run a Analog to Digital conversion
 * Returns: none
 * Notes: none
 **************************************************/
uint16_t adc_result_10bit(uint8_t channel)
{ /* 0..7 = ADC0..ADC7, respectively */
    uint16_t value = 0; /* return value */

    while (ADCSRA & (1 << ADSC))
        ;
    ADMUX = channel | (0 << ADLAR) | (0 << REFS1) | (1 << REFS0);
    /* Delay needed for the stabilization of the ADC input voltage */
    _delay_us(10);
    /* Start the analog to digital conversion */
    ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIF) | ADPS_10BIT;
    /* Wait for the analog to digital conversion to complete */
    while ((ADCSRA & (1 << ADIF)) == 0)
        ;
    value = ADCL;
    value |= (ADCH << 8);

    return value;
}

/**************************************************
 * Description: Initializes the Analog to Digital Converter
 * Returns: none
 * Notes: none
 **************************************************/
void adc_init(void)
{
    /* configure ADC for Free Running Mode - ADTS = 000 */
    /* AIN1 is applied to the negative input of the Analog Comparator - ACME */
    BITMASK_CLEAR(ADCSRB, _BV(ACME) | _BV(ADTS2) | _BV(ADTS1) | _BV(ADTS0));
    /* Digital input not needed on ADC0, so disable it to save power */
    BIT_SET(DIDR0, ADC0D);
    /* Clear the Power Reduction bit to enable ADC */
    BIT_CLEAR(PRR, PRADC);
}
